package com.xcity.game.skill;

import java.text.MessageFormat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.annotation.JSONField;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.skill.state.Phase;
import com.xcity.game.skill.state.State;
import com.xcity.game.skill.template.SkillTemplate;

import naga.x.App;
import naga.x.common.Updatable;
import naga.x.db.type.PropertyPool;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;

@Deprecated
public class PlayerSkill implements Updatable, Skill {

	protected int id;
	protected int exp; // 累计时长（秒）
	protected int level;
	protected State state;
	protected SkillPhase phase;
	protected PropertyPool pool;
	
	@JSONField(serialize = false)
	protected long lastAddExpTime;
	@JSONField(serialize = false)
	protected SkillTemplate template;
	@JSONField(serialize = false)
	protected SkillManager vm;
	
	protected static final Logger LOG = LoggerFactory.getLogger(PlayerSkill.class);
	
	public static class SkillPhase {
		public Phase id;
		public byte state; // @see Phase#STATE_xxx
		public SkillPhase() {}
		private SkillPhase(Phase id, byte state) {
			this.id = id;
			this.state = state;
		}
	}
	
	public PlayerSkill() {}
	
	public PlayerSkill(SkillManager vm, SkillTemplate template) {
		this.vm = vm;
		this.id = template.getId();
		this.template = template;
		this.exp = this.level = 0;
		// 20170331 removed, no use
//		this.state = State.DISABLE;
//		this.phase = new SkillPhase(Phase.LEARN, Phase.STATE_PAUSED);
		
		this.state = State.ACTIVATED;
		this.phase = new SkillPhase(Phase.STUDY, Phase.STATE_RUNNING);
	}

	@Override
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getExp() {
		return exp;
	}

	public void setExp(int exp) {
		this.exp = exp;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public SkillPhase getPhase() {
		return phase;
	}

	public void setPhase(SkillPhase phase) {
		this.phase = phase;
	}

	@Override
	public SkillTemplate getTemplate() {
		return template != null ? template : (template = App.getApp().getServiceManager().get(TemplateService.class).get(SkillTemplate.class, id));
	}

	public PropertyPool getPool() {
		return pool;
	}

	public void setPool(PropertyPool pool) {
		this.pool = pool;
	}
	
	public SkillManager getVm() {
		return vm;
	}
	
	@Override
	public String getName() {
		return getTemplate().getName();
	}
	
	@Override
	public String getIcon() {
		return getTemplate().getIcon();
	}
	
	@Override
	public String getDesc() {
		String desc = getTemplate().getDesc();
		Object[] vals = getTemplate().getValues(level);
		if (vals != null && vals.length > 0) {
			desc = MessageFormat.format(desc, vals);
		}
		return desc;
	}
	
	public int getMaxLevel() {
		return getTemplate().getMaxLevel();
	}
	
//	public int getMaxExp() {
//		return level < getMaxLevel() ? getTemplate().getNeedExp(level + 1) : getTemplate().getNeedExp(level);
//	}
	
	/**
	 * 当前等级槽经验，非累计（单位：秒）
	 * @return
	 */
	public int getExp0() {
//		int n = level >= getMaxLevel()
//				? getTemplate().getNeedExp(getMaxLevel() - 1)
//				: (level > 0 ? getTemplate().getNeedExp(level) : 0);
//		int val = exp - n;
//		if (val < 0) { // 配置表改变后可能导致该数值为负，需修正等级
//			level = getTemplate().ofLevel(exp);
//			n = level >= getMaxLevel()
//					? getTemplate().getNeedExp(getMaxLevel() - 1)
//					: (level > 0 ? getTemplate().getNeedExp(level) : 0);
//			val = exp - n;
//		}
//		return val;
		return 0;
	}
	
	/**
	 * 当前等级槽最大经验（单位：秒）
	 * @return
	 */
	public int getMaxExp() {
//		int nextLvl = level < getMaxLevel() ? level + 1 : level;
//		int val = nextLvl > 1 ? getTemplate().getNeedExp(nextLvl) - getTemplate().getNeedExp(nextLvl - 1) : getTemplate().getNeedExp(nextLvl);
//		return val;
		return 0;
	}
	
	public boolean addExp(int val, String cause) {
//		int maxLvl;
//		if (val <= 0 || level >= (maxLvl = getMaxLevel())) {
//			return false;
//		}
//		int oldExp = exp;
//		exp += val;
//		int oldLvl = level;
//		for (;;) {
//			int nextLvlNeedExp = getTemplate().getNeedExp(level + 1);
//			if (exp < nextLvlNeedExp) {
//				break;
//			}
//			++level;
//		}
//		if (level > oldLvl) {
//			if (Phase.getPhaseByLevel(level) != phase.id) {
//				phase.id = Phase.getPhaseByLevel(level);
//				if (state == State.DISABLE) { // reset state
//					state = State.UNACTIVATED;
//				}
//			}
//			pausePhaseLearn0(Cause.LEVEL_UP);
//		}
//		if (level >= maxLvl) {
//			pausePhaseLearn0(Cause.LEVEL_UP);
//		}
//		LOG.info("[SKILL ADDEXP]ID[{}]SKILL[{}]OLD[{}]NEW[{}]LVL[{}]CAUSE[{}]", getVm().getOwner().getId(), getId(), oldExp, exp, level, cause);
		return false;
	}
	
	public void changeState(State state) throws SkillException {
		if (state == State.DISABLE || state == null) {
			throw new SkillException(MessageConst.ILLEGAL_OPERATION);
		}
		if (this.phase.id == Phase.LEARN) { // 学习阶段不可手动切换状态
			throw new SkillException(MessageFormat.format(MessageConst.SKILL_DISABLE, getName()));
		}
		if (this.state == state) {
			return;
		}
		this.state = state;
		if (state == State.ACTIVATED) {
			// 激活状态下无法进修
			if (phase.id == Phase.STUDY && phase.state == Phase.STATE_RUNNING) {
				pausePhaseLearn(Cause.STATE_SWITCH);
			}
		} else {
			// 未激活状态下无法实践
			if (phase.id == Phase.PRACTICE && phase.state == Phase.STATE_RUNNING) {
				pausePhaseLearn(Cause.STATE_SWITCH);
			}
		}
	}
	
	@Override
	public boolean update() {
		return update(false, Cause.AUTO);
	}
	
	public boolean update(boolean force, String cause) {
		if (phase.state != Phase.STATE_RUNNING || lastAddExpTime <= 0) {
			return false;
		}
		long elapse = TimeUpdater.getInstance().now() - lastAddExpTime;
		if (force || elapse >= 10000) { // 每10秒累加一次
			lastAddExpTime = TimeUpdater.getInstance().now();
			addExp((int) (elapse / 1000), cause);
		}
		return true;
	}
	
	private void pausePhaseLearn0(String cause) {
		try {
			pausePhaseLearn(cause);
		} catch (SkillException e) {
			LOG.error("[SKILL PHASE PAUSE ERROR]ID[{}]SKILL[{}]CAUSE[{}]ERROR[{}]", getVm().getOwner().getId(), getId(), cause, e.getMessage());
		}
	}
	
	protected void pausePhaseLearn(String cause) throws SkillException {
		if (phase.state == Phase.STATE_PAUSED) {
			return;
		}
		if (!phase.id.pausable) {
			throw new SkillException(MessageConst.SKILL_CAN_NOT_PAUSE_IN_LEARN_PHASE);
		}
		update(true, Cause.PAUSE); // force update
		phase.state = Phase.STATE_PAUSED;
		lastAddExpTime = 0L;
		LOG.info("[SKILL PHASE PAUSE]ID[{}]SKILL[{}]CAUSE[{}]", getVm().getOwner().getId(), getId(), cause);
	}
	
	protected void startPhaseLearn0(long time, String cause) {
		try {
			startPhaseLearn(time, cause);
		} catch (SkillException e) {
			LOG.error("[SKILL PHASE RUN ERROR]ID[{}]SKILL[{}]CAUSE[{}]ERROR[{}]", getVm().getOwner().getId(), getId(), cause, e.getMessage());
		}
	}
	
	protected void startPhaseLearn(long time, String cause) throws SkillException {
		if (phase.state == Phase.STATE_RUNNING && lastAddExpTime > 0L) {
			return;
		}
		if (state != phase.id.preconditionForRunning) {
			String preconditionName = phase.id.preconditionForRunning == State.ACTIVATED ? "启用" : "停用";
			throw new SkillException(MessageFormat.format(MessageConst.SKILL_START_PHASE_LEARN_ERROR, preconditionName, phase.id.name));
		}
		if (level >= getMaxLevel()) {
			throw new SkillException(MessageFormat.format(MessageConst.SKILL_LEVEL_FULL, getName()));
		}
		phase.state = Phase.STATE_RUNNING;
		lastAddExpTime = time;
		LOG.info("[SKILL PHASE RUN]ID[{}]SKILL[{}]CAUSE[{}]", getVm().getOwner().getId(), getId(), cause);
	}
	
	/**
	 * 阶段学习cd偏移修正(秒)<br/>
	 * 客户端需要
	 * @return
	 */
	public int getExpOffset() {
		return (int) (lastAddExpTime > 0L ? (TimeUpdater.getInstance().now() - lastAddExpTime) / 1000 : 0);
	}

	@Override
	public boolean addLevel(int val, String cause) {
		return false;
	}

	@Override
	public float getParameter(int index) {
		return 0;
	}
	
}
